/*
**************************************************************************************
*Myriad Engine                                                                       *
*Copyright (C) 2006-2007, 5d Studios (www.5d-Studios.com)                            *
*                                                                                    *
*This library is free software; you can redistribute it and/or                       *
*modify it under the terms of the GNU Lesser General Public                          *
*License as published by the Free Software Foundation; either                        *
*version 2.1 of the License, or (at your option) any later version.                  *
*                                                                                    *
*This library is distributed in the hope that it will be useful,                     *
*but WITHOUT ANY WARRANTY; without even the implied warranty of                      *
*MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU                   *
*Lesser General Public License for more details.                                     *
*                                                                                    *
*You should have received a copy of the GNU Lesser General Public                    *
*License along with this library; if not, write to the Free Software                 *
*Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA      *
**************************************************************************************
*/
package leola.lang.collection;

import java.util.List;

import leola.backend.interpreter.Callstack;
import leola.backend.interpreter.Scope;
import leola.backend.interpreter.SymbolStack;
import leola.frontend.Leola;
import leola.frontend.LeolaLibrary;
import leola.types.LeoArray;
import leola.types.LeoFunction;
import leola.types.LeoNull;
import leola.types.LeoObject;

/**
 * @author Tony
 *
 */
public class CollectionsLeolaLibrary implements LeolaLibrary {

	/* (non-Javadoc)
	 * @see leola.frontend.LeolaLibrary#init(leola.frontend.Leola)
	 */
	@Override
	public void init(Leola leola) throws Exception {
		leola.getInterpreter().loadClass(CollectionsLeolaLibrary.class);
		leola.eval(CollectionsLeolaLibrary.class.getResourceAsStream("collections.leola"));
	}

	/**
	 * Get the rest of the array (truncating the first element
	 * 
	 * @param array
	 * @return
	 */
	public static LeoObject rest(LeoArray array) {
		if ( array == null || array.getArray().size() < 2 ) {
			return LeoNull.LEONULL;
		}
		else {
			List<LeoObject> list = array.getArray();
			return new LeoArray(list.subList(1, list.size()));
		}
	}
	
	/**
	 * Retrieves the first element in the list.
	 * 
	 * @param array
	 * @return
	 */
	public static LeoObject first(LeoArray array) {
		if ( array == null || array.getArray().isEmpty() ) {
			return LeoNull.LEONULL;
		}
		else {
			List<LeoObject> list = array.getArray();
			return list.get(0);
		}		
	}
	
	/**
	 * Appends an object to the array.
	 * 
	 * @param array - allowed to be null, if null creates a new array.
	 * @param obj
	 * @return the array 
	 */
	public static LeoObject append(LeoArray array, LeoObject obj /*, LeoObject ...leoObjects*/ ) {
		if ( array == null ) {
			array = new LeoArray();
		}
		
		array.add(obj);
		/*
		if ( leoObjects != null ) {
			for(LeoObject o: leoObjects) {
				array.add(o);
			}
		}*/
		
		return array;
	}
	
	/**
	 * Removes an element from the array.
	 * 
	 * @param array
	 * @param obj
	 * @return
	 */
	public static LeoObject remove(LeoArray array, LeoObject obj) {
		if ( array != null ) {
			array.getArray().remove(obj);
		}
		return array;
	}
	
	/**
	 * Iterates through the array invoking the call back.
	 * 
	 * @param array
	 * @param function
	 * @throws Exception
	 */
	public static final void __foreach(Leola leola, LeoArray array, LeoFunction function) throws Exception {
		List<LeoObject> list = array.getArray();
		int size = list.size();
		
		Callstack stack = leola.getInterpreter().getCallstack();
		SymbolStack symStack = leola.getInterpreter().getSymbolStack();
		Scope functionScope = new Scope(true, function);
		symStack.push(functionScope);
		
		for(int i = 0; i < size; i++) {
			int stackSize = stack.size();
			//stack.push(list.get(i));
			leola.getInterpreter().executeFunction(function, list.get(i));	
			
			/* If there is an object put on the stack
			 * lets check for 'break'
			 */
			if ( stack.size() > stackSize ) {
				LeoObject obj = stack.pop();
				if ( obj.isTrue() ) {
					break;
				}
			}
		}
		
		symStack.pop();
	}
	
	
	/**
	 * Iterates through the array invoking the call back filling the
	 * array
	 * 
	 * @param array
	 * @param function
	 * @throws Exception
	 */
	public static final void __fill(Leola leola, LeoArray array, LeoFunction function) throws Exception {
		List<LeoObject> list = array.getArray();
		int size = list.size();
		
		Callstack stack = leola.getInterpreter().getCallstack();
		SymbolStack symStack = leola.getInterpreter().getSymbolStack();
		Scope functionScope = new Scope(true, function);
		symStack.push(functionScope);
		
		for(int i = 0; i < size; i++) {			
			leola.getInterpreter().executeFunction(function);	
			
			LeoObject obj = stack.pop();
			list.set(i, obj);					
		}
		
		symStack.pop();
	}
}
